import { Board } from '../board'
import { BoardBase, BoardPiece } from '@kenrick95/c4'
import {
  GameBase,
  MESSAGE_TYPE,
  constructMessage,
  parseMessage,
  GameOnlineMessage,
} from '@kenrick95/c4'
import { Player, PlayerHuman, PlayerShadow } from '@kenrick95/c4'
import { getColumnFromCoord } from '@kenrick95/c4'
import { showMessage } from '../utils/message'

enum GAME_MODE {
  FIRST = BoardPiece.PLAYER_1,
  SECOND = BoardPiece.PLAYER_2,
}

const statusbox = document.querySelector('.statusbox')
const statusboxBodyGame = document.querySelector('.statusbox-body-game')
const statusboxBodyConnection = document.querySelector(
  '.statusbox-body-connection',
)
const statusboxBodyPlayer = document.querySelector('.statusbox-body-player')

// const C4_SERVER_ENDPOINT =
//   import.meta.env.MODE === 'production'
//     ? import.meta.env.C4_SERVER_ENDPOINT
//       ? import.meta.env.C4_SERVER_ENDPOINT
//       : `wss://c4-server.fly.dev/`
//     : `ws://${location.hostname}:8080`


const C4_SERVER_ENDPOINT = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}/` 

export class GameOnline2p extends GameBase {
  connectionPlayerId: null | string = null
  connectionMatchId: null | string = null
  ws: null | WebSocket = null
  gameMode: GAME_MODE

  playerMain: PlayerHuman
  playerShadow: PlayerShadow

  constructor(
    players: Array<Player>,
    board: BoardBase,
    { gameMode, playerName }: { gameMode: GAME_MODE; playerName: string },
  ) {
    super(players, board)
    this.gameMode = gameMode
    if (gameMode === GAME_MODE.FIRST) {
      this.playerMain = players[0] as PlayerHuman
      this.playerShadow = players[1] as PlayerShadow
    } else {
      this.playerMain = players[1] as PlayerHuman
      this.playerShadow = players[0] as PlayerShadow
    }
    this.playerMain.label = playerName
    this.initConnection()
  }

  end() {
    super.end()
    this.endConnection()
  }

  endConnection() {
    if (this.ws) {
      this.ws.close()
    }
  }

  initConnection() {
    console.log('initConnection')
    this.connectionPlayerId = null
    this.connectionMatchId = null
    if (this.ws) {
      this.ws.close()
    }

    const setStatusDisconnected = () => {
      this.isMoveAllowed = false
      if (statusboxBodyConnection) {
        statusboxBodyConnection.textContent = '与服务器断开连接'
      }
      if (statusboxBodyGame) {
        statusboxBodyGame.textContent = `游戏结束`
      }
      if (statusboxBodyPlayer) {
        statusboxBodyPlayer.textContent = `已离开对局`
      }
    }

    this.ws = new WebSocket(C4_SERVER_ENDPOINT)
    this.ws.addEventListener('message', (event) => {
      this.messageActionHandler(parseMessage(event.data))
    })
    this.ws.addEventListener('open', () => {
      if (this.ws) {
        this.ws.send(
          constructMessage(MESSAGE_TYPE.NEW_PLAYER_CONNECTION_REQUEST, {
            playerName: this.playerMain.label,
          }),
        )
      }
      if (statusboxBodyConnection) {
        statusboxBodyConnection.textContent = '已连接到服务器'
      }
      if (statusboxBodyGame) {
        statusboxBodyGame.textContent = ``
      }
      if (statusboxBodyPlayer) {
        statusboxBodyPlayer.textContent = ``
      }
    })
    this.ws.addEventListener('close', (event) => {
      console.log('[ws] 关闭事件', event)
      setStatusDisconnected()
    })
    this.ws.addEventListener('error', (event) => {
      console.log('[ws] 错误事件', event)
      setStatusDisconnected()
    })
  }

  initMatch = () => {
    if (this.ws) {
      this.ws.send(
        constructMessage(MESSAGE_TYPE.NEW_MATCH_REQUEST, {
          playerId: this.connectionPlayerId,
        }),
      )
    }
  }

  connectToMatch = (matchId: string) => {
    if (!this.ws) {
      return
    }
    this.ws.send(
      constructMessage(MESSAGE_TYPE.CONNECT_MATCH_REQUEST, {
        playerId: this.connectionPlayerId,
        matchId,
      }),
    )
  }

  messageActionHandler = (message: GameOnlineMessage) => {
    switch (message.type) {
      case MESSAGE_TYPE.NEW_PLAYER_CONNECTION_OK:
        {
          this.connectionPlayerId = message.payload.playerId
          if (this.gameMode === GAME_MODE.FIRST) {
            this.initMatch()
          } else if (this.gameMode === GAME_MODE.SECOND) {
            // there is a matchid in URL
            const searchParams = new URLSearchParams(location.search)
            const connectionMatchId = searchParams.get('matchId')
            if (!connectionMatchId) {
              return
            }
            this.connectToMatch(connectionMatchId)
          }
        }
        break
      case MESSAGE_TYPE.NEW_MATCH_OK:
        {
          this.connectionMatchId = message.payload.matchId
          const shareUrl = `${location.href}?matchId=${this.connectionMatchId}`
          // TODO: button to copy share url again?
          console.log('[url] 分享此', shareUrl)
          showMessage(
            `<h1>分享此链接</h1>` +
              `<p>` +
              `请将此链接分享给你的朋友以开始游戏：` +
              `<input type="text" id="copy-box" class="copy-box" readonly value="${shareUrl}" />` +
              `<button type="button" id="copy-button">复制</button>` +
              `</p>`,
          )
          // Select all
          const copyBox: HTMLInputElement | null = document.getElementById(
            'copy-box',
          ) as HTMLInputElement
          copyBox.focus()
          copyBox.select()

          // Click to copy
          document
            .getElementById('copy-button')
            ?.addEventListener('click', async () => {
              let isClipboardApiSuccessful = false

              if (navigator.clipboard) {
                try {
                  await navigator.clipboard.writeText(shareUrl)
                  console.log(
                    '正在使用剪贴板 API 将分享链接写入剪贴板',
                  )
                  isClipboardApiSuccessful = true
                } catch (err) {}
              }

              if (!isClipboardApiSuccessful) {
                // Old method: use as fallback
                copyBox?.select()
                copyBox?.setSelectionRange(0, 99999)
                document.execCommand('copy')
                console.log(
                  '正在使用备用方法将分享链接写入剪贴板',
                )
              }
            })
        }
        break
      case MESSAGE_TYPE.CONNECT_MATCH_OK:
        {
          this.connectionMatchId = message.payload.matchId
        }
        break
      case MESSAGE_TYPE.CONNECT_MATCH_FAIL:
        {
          showMessage(`<h1>错误</h1> 无法连接到对局。`)

          if (statusboxBodyConnection) {
            statusboxBodyConnection.textContent = '连接错误'
          }
        }
        break
      case MESSAGE_TYPE.GAME_READY:
        {
          this.playerShadow.label = message.payload.otherPlayerName
          showMessage(
            `<h1>游戏已开始</h1> 首枚棋子落子者： ${
              this.isCurrentMoveByCurrentPlayer() ? '你' : '对方玩家'
            }`,
          )

          if (statusboxBodyGame) {
            statusboxBodyGame.textContent = '等待操作'
          }

          if (statusboxBodyPlayer) {
            const currentPlayer = this.players[this.currentPlayerId]
            statusboxBodyPlayer.textContent =
              `${currentPlayer.label} ${currentPlayer.boardPiece}` +
              ` ` +
              (this.isCurrentMoveByCurrentPlayer()
                ? `(你)`
                : `(对方玩家)`)
          }
          this.start()
        }
        break
      case MESSAGE_TYPE.MOVE_SHADOW:
        {
          this.playerShadow.doAction(message.payload.column)
        }
        break
      case MESSAGE_TYPE.GAME_ENDED:
        {
          const { winnerBoardPiece } = message.payload

          let winnerPlayer = this.players.find(
            (player) => player.boardPiece === winnerBoardPiece,
          )

          const messageWinner =
            winnerBoardPiece === BoardPiece.DRAW
              ? `平局`
              : winnerPlayer
                ? `${winnerPlayer.label} ${winnerPlayer.boardPiece} 获胜`
                : `玩家 ${
                    winnerBoardPiece === BoardPiece.PLAYER_1 ? '1 🔴' : '2 🔵'
                  } 获胜`

          showMessage(
            `<h1>感谢游玩</h1>` +
              messageWinner +
              `<br />下一局将在 10 秒后开始。`,
          )

          if (statusboxBodyGame) {
            statusboxBodyGame.textContent = '游戏结束'
          }
          if (statusboxBodyPlayer) {
            statusboxBodyPlayer.textContent = messageWinner
          }
        }
        break
      case MESSAGE_TYPE.GAME_RESET:
        {
          this.reset()
        }
        break

      case MESSAGE_TYPE.OTHER_PLAYER_HUNGUP:
        {
          showMessage(
            `<h1>对方玩家已断开连接</h1> 请刷新页面以开始新的对局`,
          )
        }
        break
    }
  }

  /**
   * @returns true if the game is waiting for current player to make a move
   */
  isCurrentMoveByCurrentPlayer() {
    if (this.gameMode === GAME_MODE.FIRST) {
      return this.currentPlayerId === 0
    } else {
      return this.currentPlayerId === 1
    }
  }

  beforeMoveApplied = () => {
    if (statusboxBodyGame) {
      const currentPlayer = this.players[this.currentPlayerId]
      statusboxBodyGame.textContent = `玩家 ${currentPlayer.boardPiece} 正在落子`
    }
  }

  waitingForMove = () => {
    if (statusboxBodyGame) {
      statusboxBodyGame.textContent = '等待操作'
    }

    if (statusboxBodyPlayer) {
      const currentPlayer = this.players[this.currentPlayerId]
      statusboxBodyPlayer.textContent =
        `${currentPlayer.label} ${currentPlayer.boardPiece}` +
        ` ` +
        (this.isCurrentMoveByCurrentPlayer() ? `(你)` : `(对方玩家)`)
    }
  }

  afterMove = (action: number) => {
    if (this.ws && this.isCurrentMoveByCurrentPlayer()) {
      this.ws.send(
        constructMessage(MESSAGE_TYPE.MOVE_MAIN, {
          playerId: this.connectionPlayerId,
          matchId: this.connectionMatchId,
          column: action,
        }),
      )
    }
  }

  announceWinner(winnerBoardPiece: BoardPiece) {
    super.announceWinner(winnerBoardPiece)
    // Do nothing here, will wait for server to announce
  }
}

export function initGameOnline2p(playerName: string) {
  const canvas = document.querySelector('canvas')
  if (!canvas) {
    console.error('Canvas DOM 元素为空')
    return
  }

  const searchParams = new URLSearchParams(location.search)
  const connectionMatchId = searchParams.get('matchId')
  const gameMode = !!connectionMatchId ? GAME_MODE.SECOND : GAME_MODE.FIRST

  const board = new Board(canvas)
  const players =
    gameMode === GAME_MODE.FIRST
      ? [
          new PlayerHuman(BoardPiece.PLAYER_1, playerName),
          new PlayerShadow(BoardPiece.PLAYER_2, `对方玩家`),
        ]
      : [
          new PlayerShadow(BoardPiece.PLAYER_1, `对方玩家`),
          new PlayerHuman(BoardPiece.PLAYER_2, playerName),
        ]

  const game = new GameOnline2p(players, board, {
    gameMode,
    playerName,
  })
  statusbox?.classList.remove('hidden')
  statusboxBodyConnection?.classList.remove('hidden')

  async function handleCanvasClick(event: MouseEvent) {
    if (!game.isGameWon) {
      if (!canvas) {
        return
      }
      const rect = canvas.getBoundingClientRect()
      const x = event.clientX - rect.left
      const y = event.clientY - rect.top
      const column = getColumnFromCoord({ x: x, y: y })
      game.playerMain.doAction(column)
    }
  }

  canvas.addEventListener('click', handleCanvasClick)

  return {
    end: () => {
      game.end()
      canvas.removeEventListener('click', handleCanvasClick)
      statusbox?.classList.add('hidden')
    },
  }
}
